昨天角色的 CRUD 功能都完成了,接著就是要把角色指派給使用者了,先建立一個 ViewModel CustomUserRoleViewModel
,這是用來呈現角色底下使用者的 ViewModel。
namespace BlazorServer.ViewModels
{
public class CustomUserRoleViewModel
{
public string UserId { get; set; }
public string UserName { get; set; }
public bool IsSelected { get; set; }
}
}
再於IRolesRepository
跟RolesRepository
加上編輯角色內使用者的功能,這裡用了多載,第一個相當於 Get 取得畫面初始資料,第二個則是 Post 送出修改後的資料。IRolesRepository.cs
…
Task<List<CustomUserRoleViewModel>> EditUsersInRoleAsync(string RoleId);
Task<ResultViewModel> EditUsersInRoleAsync(List<CustomUserRoleViewModel> model, string RoleId);
RolesRepository.cs
…
public async Task<List<CustomUserRoleViewModel>> EditUsersInRoleAsync(string RoleId)
{
var role = await _roleManager.FindByIdAsync(RoleId);
var model = new List<CustomUserRoleViewModel>();
foreach (var user in _userManager.Users)
{
var userRoleViewModel = new CustomUserRoleViewModel
{
UserId = user.Id,
UserName = user.UserName
};
if (await _userManager.IsInRoleAsync(user, role.Name))
{
userRoleViewModel.IsSelected = true;
}
else
{
userRoleViewModel.IsSelected = false;
}
model.Add(userRoleViewModel);
}
return model;
}
public async Task<ResultViewModel> EditUsersInRoleAsync(List<CustomUserRoleViewModel> model, string RoleId)
{
var role = await _roleManager.FindByIdAsync(RoleId);
foreach (var m in model)
{
var user = await _userManager.FindByIdAsync(m.UserId);
IdentityResult result;
if (m.IsSelected && !(await _userManager.IsInRoleAsync(user, role.Name)))
{
result = await _userManager.AddToRoleAsync(user, role.Name);
}
else if (!m.IsSelected && await _userManager.IsInRoleAsync(user, role.Name))
{
result = await _userManager.RemoveFromRoleAsync(user, role.Name);
}
else
{
continue;
}
if (result.Succeeded)
{
if (model.Count > 0)
{
continue;
}
else
{
return new ResultViewModel
{
Message = RoleId,
IsSuccess = true
};
}
}
else
{
return new ResultViewModel
{
Message = RoleId,
IsSuccess = false
};
}
}
return new ResultViewModel
{
Message = RoleId,
IsSuccess = true
};
}
接著加上畫面。EditUsersInRole.razor.cs
using BlazorServer.Services;
using BlazorServer.Shared;
using BlazorServer.ViewModels;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorServer.Pages.RolesManagement
{
public partial class EditUsersInRole
{
[Inject] protected IRolesRepository RolesRepository { get; set; }
[Inject] protected NavigationManager NavigationManager { get; set; }
[Inject] protected IJSRuntime js { get; set; }
private JsInteropClasses jsClass;
[Parameter]
public string RoleId { get; set; }
public List<CustomUserRoleViewModel> UserRoleViewModel { get; set; } = new List<CustomUserRoleViewModel>();
protected override async Task OnInitializedAsync()
{
await loadData();
jsClass = new(js);
}
private async Task loadData()
{
UserRoleViewModel = (await RolesRepository.EditUsersInRoleAsync(RoleId)).ToList();
}
public async Task HandleValidSubmit()
{
var result = await RolesRepository.EditUsersInRoleAsync(UserRoleViewModel, RoleId);
if (result.IsSuccess)
{
NavigationManager.NavigateTo($"/RolesManagement/EditRole/{RoleId}");
}
else
{
await jsClass.Alert(result.Message);
}
}
public void Cancel()
{
NavigationManager.NavigateTo($"/RolesManagement/EditRole/{RoleId}");
}
}
}
EditUsersInRole.razor
@attribute [Authorize]
<EditForm Model="UserRoleViewModel" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="card">
<div class="card-header">
<h2>從角色新增或移除使用者</h2>
</div>
<div class="card-body">
@foreach (var user in UserRoleViewModel)
{
<div class="form-check m-1">
<label class="form-check-label">
<InputCheckbox @bind-Value="@user.IsSelected"></InputCheckbox>
@user.UserName
</label>
</div>
}
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary">更新</button>
<button type="button" class="btn btn-danger" @onclick="@Cancel">取消</button>
</div>
</div>
</EditForm>
EditRole.razor.cs
新增一個方法,通往EditUsersInRole.razor
,可以編輯角色底下使用者。
public void EditUsersInRole()
{
NavigationManager.NavigateTo($"/RolesManagement/EditUsersInRole/{RoleId}");
}
EditRole.razor
加上一個按鈕呼叫該方法。
<button type="button" class="btn btn-info" @onclick="EditUsersInRole">新增或移除該角色底下的使用者</button>
啟動網頁進入編輯角色下使用者頁面,可以看到目前只有一個使用者,將Admin
角色指派給這個使用者,如此一來就完成了Admin
跟test@gmail.com
的指派,不過要測試是否成功的話,需要對頁面加入限制,還要新增一個使用者測試。
先將每個 razor component 的@attribute [Authorize]
改成@attribute [Authorize(Roles = "Admin")]
,表示要看到這頁面的人必須有 Role Admin
。
再去NavMenu.razor
,於原本的<AuthorizeView>
上方加入下面這段程式,同理要看到通往Roles
連結的人必須有 Role Admin
,再把原本<AuthorizeView>
的Roles
連結刪除。
<AuthorizeView Roles="Admin">
<Authorized>
<li class="nav-item px-3">
<NavLink class="nav-link" href="RolesManagement/RolesList" Match="NavLinkMatch.All">
<span class="bi bi-kanban-fill h4 p-2 mb-0" aria-hidden="true"></span> Roles
</NavLink>
</li>
</Authorized>
</AuthorizeView>
最後新增一名使用者,名為user@gmail.com
,以此使用者登入,會發現左邊的Roles
不見了,手動輸入網址也會提示沒有權限,這就是最基本的角色(Role)授權,如果系統很簡單只要用角色劃分權限,這樣就能滿足需求了。
Ref:Add or remove users from role in asp net core